/**
 * Project Name:template-web
 * File Name   :TokenInterceptor.java
 * Package Name:org.cn.template.component.web.interceptor
 * Date:2015年9月27日下午4:28:26
 * Copyright (c) 2015, http://my.oschina.net/httpssl All Rights Reserved.
 *
*/

package org.cn.template.component.web.interceptor;

import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.cn.template.component.Contains;
import org.cn.template.component.annotation.Token;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

/**
 * ClassName:TokenInterceptor <br/>
 * Function :TODO ADD FUNCTION. <br/>
 * Reason :TODO ADD REASON. <br/>
 * Date :2015年9月27日 下午4:28:26 <br/>
 * 
 * @author :http://my.oschina.net/httpssl
 * @email :491835898@QQ.COM
 * @since :JDK 1.7
 * @see
 * 防表单重复提交
 */
public class TokenInterceptor extends HandlerInterceptorAdapter
{

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// 如果是get请求则不作处理
		if (request.getMethod().equalsIgnoreCase("GET")) {
			return super.preHandle(request, response, handler);
		}
		// 如果方法有@Token注解
		if (hasTokenMethod(handler)) {
			// 如果是重复提交
			if (sameRequest(request, response)) {
				// 异常
				throw new Exception("非法请求");
			}
		}
		return super.preHandle(request, response, handler);
	}

	/**
	 * 请求到达页面之前，生成一个token并保存在request和session中
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		// TODO Auto-generated method stub
		// 如果是一次有页面渲染的请求，就给该页面生成Token
		if (modelAndView != null) {
			String uuid = UUID.randomUUID().toString();
			request.setAttribute(Contains.TOKEN, uuid);
			request.getSession().setAttribute(Contains.TOKEN, uuid);
		}
		super.postHandle(request, response, handler, modelAndView);
	}

	/**
	 * @Title: sameRequest
	 * @Description: 是否是同一个请求
	 * @param request
	 * @return boolean
	 */
	private boolean sameRequest(HttpServletRequest request, HttpServletResponse response) {
		// 获取请求到达页面时生成的token
		String token_mark = Contains.TOKEN;
		String clientToken = request.getParameter(Contains.TOKEN);
		if (StringUtils.isBlank(clientToken)) {
			clientToken = request.getParameter("state");
		}
		String serverToken = (String) request.getSession().getAttribute(token_mark);
		// 如果客户端或服务端没有token则不许提交
		if (StringUtils.isBlank(clientToken) || StringUtils.isBlank(serverToken)) {
			return true;
		}
		// 如果token不相同则提交表单，并且更新页面的token值
		if (serverToken.equals(clientToken)) {
			return false;
		}
		return true;
	}

	/**
	 * @Title: hasTokenMethod
	 * @Description: 判断是否是一个有@Token注解的方法
	 * @param handler
	 * @return boolean
	 */
	private boolean hasTokenMethod(Object handler) {
		if (handler instanceof HandlerMethod) {
			HandlerMethod handlerMethod = (HandlerMethod) handler;
			Token annotation = handlerMethod.getMethodAnnotation(Token.class);
			if (annotation != null) {
				return true;
			}
		}
		return false;
	}
}
